

<!DOCTYPE html>
<html lang="zh-CN" data-default-color-scheme=&#34;auto&#34;>



<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/img/favicon.png">
  <link rel="icon" type="image/png" href="/img/favicon.png">
  <meta name="viewport"
        content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="description" content="">
  <meta name="author" content="Lin">
  <meta name="keywords" content="">
  <title>多线程之 Synchronized - Vin</title>

  <link  rel="stylesheet" href="https://cdn.staticfile.org/twitter-bootstrap/4.5.3/css/bootstrap.min.css" />


  <link  rel="stylesheet" href="https://cdn.staticfile.org/github-markdown-css/4.0.0/github-markdown.min.css" />
  <link  rel="stylesheet" href="/lib/hint/hint.min.css" />

  
    
    
      
      <link  rel="stylesheet" href="https://cdn.staticfile.org/highlight.js/10.1.2/styles/androidstudio.min.css" />
    
  

  
    <link  rel="stylesheet" href="https://cdn.staticfile.org/fancybox/3.5.7/jquery.fancybox.min.css" />
  



<!-- 主题依赖的图标库，不要自行修改 -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_ba1fz6golrf.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_kmeydafke9r.css">


<link  rel="stylesheet" href="/css/main.css" />

<!-- 自定义样式保持在最底部 -->

  
<link rel="stylesheet" href="/css/custom.css">



  <script id="fluid-configs">
    var Fluid = window.Fluid || {};
    var CONFIG = {"hostname":"example.com","root":"/","version":"1.8.5","typing":{"enable":true,"typeSpeed":50,"cursorChar":"_","loop":false},"toc":{"enable":true,"headingSelector":"h1,h2,h3,h4,h5,h6","collapseDepth":0},"anchorjs":{"enable":false,"element":"h1,h2,h3,h4,h5,h6","placement":"right","visible":"hover","icon":""},"copy_btn":true,"image_zoom":{"enable":true},"lazyload":{"enable":true,"onlypost":false},"web_analytics":{"enable":false,"baidu":null,"google":null,"gtag":null,"tencent":{"sid":null,"cid":null},"woyaola":null,"cnzz":null,"leancloud":{"app_id":null,"app_key":null,"server_url":null}}};
  </script>
  <script  src="/js/utils.js" ></script>
  <script  src="/js/color-schema.js" ></script>
<meta name="generator" content="Hexo 5.2.0"></head>


<body>
  <header style="height: 60vh;">
    <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand"
       href="/">&nbsp;<strong>Vin's Blog</strong>&nbsp;</a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/">
                <i class="iconfont icon-home-fill"></i>
                首页
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/archives/">
                <i class="iconfont icon-archive-fill"></i>
                归档
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/categories/">
                <i class="iconfont icon-category-fill"></i>
                分类
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/tags/">
                <i class="iconfont icon-tags-fill"></i>
                标签
              </a>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" data-toggle="modal" data-target="#modalSearch">&nbsp;<i
                class="iconfont icon-search"></i>&nbsp;</a>
          </li>
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" href="javascript:">&nbsp;<i
                class="iconfont icon-dark" id="color-toggle-icon"></i>&nbsp;</a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

    <div class="banner intro-2" id="background" parallax=true
         style="background: url('https://cdn.jsdelivr.net/gh/vin9712/cdnRes@cdn/blog/hexo/img/2020/20201001115214.jpg') no-repeat center center;
           background-size: cover;">
      <div class="full-bg-img">
        <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
          <div class="page-header text-center fade-in-up">
            <span class="h2" id="subtitle" title="多线程之 Synchronized">
              
            </span>

            
              <div class="mt-3">
  
  
    <span class="post-meta">
      <i class="iconfont icon-date-fill" aria-hidden="true"></i>
      <time datetime="2020-09-30 14:36" pubdate>
        2020年9月30日 下午
      </time>
    </span>
  
</div>

<div class="mt-1">
  
    
    <span class="post-meta mr-2">
      <i class="iconfont icon-chart"></i>
      1.5k 字
    </span>
  

  
    
    <span class="post-meta mr-2">
      <i class="iconfont icon-clock-fill"></i>
      
      
      16
       分钟
    </span>
  

  
  
</div>

            
          </div>

          
        </div>
      </div>
    </div>
  </header>

  <main>
    
      

<div class="container-fluid">
  <div class="row">
    <div class="d-none d-lg-block col-lg-2"></div>
    <div class="col-lg-8 nopadding-md">
      <div class="container nopadding-md" id="board-ctn">
        <div class="py-5" id="board">
          <article class="post-content mx-auto">
            <!-- SEO header -->
            <h1 style="display: none">多线程之 Synchronized</h1>
            
            <div class="markdown-body">
              <blockquote>
<p>更多详情请看: <a target="_blank" rel="noopener" href="https://juejin.im/post/6844903918653145102">https://juejin.im/post/6844903918653145102</a></p>
</blockquote>
<h3 id="1-synchronized-的作用及使用方式"><a href="#1-synchronized-的作用及使用方式" class="headerlink" title="1. synchronized 的作用及使用方式"></a>1. synchronized 的作用及使用方式</h3><p><strong>作用：确保线程<mark>互斥</mark>地访问同步代码(资源)</strong></p>
<p><strong>使用方式：</strong></p>
<ul>
<li><strong>修饰实例方法</strong>：作用于<strong>当前对象实例</strong>加锁，进入同步代码前要获得当前对象实例的锁</li>
<li><strong>修饰静态方法</strong>：作用于<strong>当前类对象</strong>加锁，进入同步代码前要获得当前类对象的锁 。也就是<strong>给当前类加锁</strong>，会作用于类的所有对象实例，因为静态成员不属于任何一个实例对象，是类成员（ static 表明这是该类的一个静态资源，不管new了多少个对象，只有一份，所以对该类的所有对象都加了锁）。所以如果一个线程A调用一个实例对象的非静态 synchronized 方法，而线程B需要调用这个实例对象所属类的静态 synchronized 方法，是允许的，不会发生互斥现象，因为访问静态 synchronized 方法占用的锁是当前类的锁，而访问非静态 synchronized 方法占用的锁是当前实例对象锁。</li>
<li><strong>修饰代码块</strong>：指定加锁对象，对给定对象加锁，进⼊同步代码库前要获得给定对象的锁。</li>
</ul>
<p><img src="https://cdn.jsdelivr.net/gh/vin9712/cdnRes@cdn/blog/hexo/img/2020/20201022000217" srcset="/img/loading.gif" alt="img"></p>
<h3 id="2-synchronized-关键字的底层原理"><a href="#2-synchronized-关键字的底层原理" class="headerlink" title="2. synchronized 关键字的底层原理"></a>2. synchronized 关键字的底层原理</h3><p>​    接下来通过编译代码来解析 synchronized 关键字执行的底层原理：</p>
<ul>
<li><p><strong>synchronized 关键字作用于<mark>代码块</mark></strong></p>
<div class="hljs"><pre class="hljs-wrap"><code data-rel="Code" class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SynchronizedTest</span> </span>&#123;
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doSth</span><span class="hljs-params">()</span></span>&#123;
        <span class="hljs-keyword">synchronized</span> (SynchronizedTest.class)&#123;
            System.out.println(<span class="hljs-string">&quot;test Synchronized&quot;</span> );
        &#125;
    &#125;
&#125;</code></pre></div>

</li>
</ul>
<p>编译后，指令执行如下</p>
<p><img src="https://cdn.jsdelivr.net/gh/vin9712/cdnRes@cdn/blog/hexo/img/2020/20201021234322.png" srcset="/img/loading.gif" alt="image-20200905122733203"></p>
<p> synchronized 同步语句块的实现使⽤的是 <strong><mark>monitorenter</mark> 和 <mark>monitorexit</mark> 指令</strong>，其中 monitorenter 指令指向同步代码块的<strong>开始位置</strong>，monitorexit 指令则指明同步代码块的<strong>结束位置</strong>。</p>
<p>  <strong>monitorenter 指令执行流程如下</strong></p>
  <pre class="hljs-wrap"><code data-rel="Code" class="hljs mermaid">graph LR
A(开始) --&gt; B(执行 monitorenter 指令)
B --&gt;|成功| C(获得 monitor 锁)
C --&gt; D(计数器+1)
D --&gt; E(结束)</code></pre>



<p>  <strong>monitorexit 指令执行流程如下</strong></p>
<pre class="hljs-wrap"><code data-rel="Code" class="hljs mermaid">graph LR
    A(开始) --&gt; B&#123;拥有 monitor 锁&#125;
    B --&gt;|是| C(执行 monitorexit 指令)
    C --&gt; D(计数器-1)
    D --&gt; E(结束)
    B --&gt;|否| E</code></pre>

<ul>
<li><strong>synchronized 关键字作用于<mark>方法</mark></strong></li>
</ul>
<div class="hljs"><pre class="hljs-wrap"><code data-rel="Code" class="hljs java"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">synchronized</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doSth</span><span class="hljs-params">()</span></span>&#123;
    	System.out.println(<span class="hljs-string">&quot;test Synchronized method&quot;</span> );
   &#125;</code></pre></div>

<p>编译后，指令执行如下</p>
<p><img src="https://cdn.jsdelivr.net/gh/vin9712/cdnRes@cdn/blog/hexo/img/2020/20201021234337.png" srcset="/img/loading.gif" alt="image-20200905125111172"></p>
<p>JVM 通过在方法访问<strong>标识符(flags)</strong> 中加入 <mark><strong>ACC_SYNCHRONIZED</strong></mark> 来实现同步功能。</p>
<p><strong>加入 ACC_SYNCHORONIZED 标识符的执行流程如下</strong></p>
<p><img src="https://cdn.jsdelivr.net/gh/vin9712/cdnRes@cdn/blog/hexo/img/2020/20201021235513.png" srcset="/img/loading.gif" alt="image-20201021235458913"></p>
<h3 id="3-JDK1-6-之后的-synchronized-关键字底层做了哪些优化-（Monitor-锁优化）"><a href="#3-JDK1-6-之后的-synchronized-关键字底层做了哪些优化-（Monitor-锁优化）" class="headerlink" title="3. JDK1.6 之后的 synchronized 关键字底层做了哪些优化?（Monitor 锁优化）"></a>3. JDK1.6 之后的 synchronized 关键字底层做了哪些优化?（Monitor 锁优化）</h3><p>JDK1.6 对锁的实现引入了大量的优化，如<strong>适应性自旋锁、锁消除、锁粗化、轻量级锁和偏向锁</strong>等技术来减少锁操作的开销。</p>
<h4 id="3-1-自旋锁"><a href="#3-1-自旋锁" class="headerlink" title="3.1 自旋锁"></a>3.1 自旋锁</h4><p>​    <strong>定义：</strong>自旋锁是指当一个线程尝试获取某个锁时，如果该锁已被其他线程占用，就<strong>一直循环检测锁是否被释放</strong>，而不是进入线程挂起或睡眠状态。</p>
<p>​    <strong>原因：</strong>线程的阻塞和唤醒需要CPU从用户态转为核心态，频繁的阻塞和唤醒显然对CPU来说苦不堪言，故引用自旋锁减少性能开销。</p>
<p>​    <strong>应用场景：</strong>锁保护的<strong>临界区很小</strong>的情况，<strong>即锁占用的时间很短</strong>的情况。如 <strong><mark>ConcurrentHashMap</mark>放弃分段锁，而使用 <mark>CAS自旋</mark> 方式。</strong></p>
<h4 id="3-2-锁清除"><a href="#3-2-锁清除" class="headerlink" title="3.2 锁清除"></a>3.2 锁清除</h4><p>​    <strong>定义：</strong>锁削除是指虚拟机即时编译器在运行时，对一些代码上要求同步，但是被检测到<strong>不可能存在共享数据竞争的锁进行<mark>削除</strong></mark>。</p>
<h4 id="3-3-锁粗化"><a href="#3-3-锁粗化" class="headerlink" title="3.3 锁粗化"></a>3.3 锁粗化</h4><p>​    <strong>定义：</strong>锁粗化是指将多个连续的加锁、解锁操作连接在一起，<strong>扩展成一个范围更大的锁</strong>。</p>
<p>​    <strong>原因：</strong>让同步块的<strong>作用范围</strong>和需要同步的<strong>操作数量</strong>尽可能小，若引入一系列的连续加锁解锁操作，减少不必要的性能损耗。</p>
<h3 id="4-synchronized-和-ReentrantLock-的区别"><a href="#4-synchronized-和-ReentrantLock-的区别" class="headerlink" title="4. synchronized 和 ReentrantLock 的区别"></a>4. synchronized 和 ReentrantLock 的区别</h3><ul>
<li><p><strong>两者都是可重入锁</strong></p>
<p><strong>可重入锁</strong>：<strong>自己可以再次获取自己的内部锁。</strong>比如一个线程获得了某个对象的锁，此时这个对象锁还没有释放，当其再次想要获取这个对象的锁的时候还是可以获取的，如果不可锁重入的话，就会造成死锁。同一个线程每次获取锁，锁的计数器都自增1，所以要等到锁的计数器下降为0时才能释放锁。</p>
</li>
</ul>
<ul>
<li><p><strong>synchronized 依赖于 JVM 而 ReenTrantLock 依赖于 API</strong></p>
<p>synchronized 是依赖于 JVM 实现的，具体实现没有直接暴露给我们程序员。</p>
<p>ReenTrantLock 是 JDK 层面实现的，需要 <strong>lock() 和 unlock() 方法配合 try/finally 语句块</strong>来完成，因此可以通过查看它的源代码，来看它是如何实现的。</p>
<p><strong>synchronized 异常就会释放锁，而 ReenTrantLock 异常需要在 finally 里 unlock()。</strong></p>
</li>
</ul>
<ul>
<li><strong>ReenTrantLock 比 synchronized 增加了一些高级功能</strong><ul>
<li><strong>等待可中断：中断等待锁的线程的机制</strong>，通过lock.lockInterruptibly()来实现这个机制。也就是说正在等待的线程可以选择放弃等待，改为处理其他事情。</li>
<li><strong>可实现公平锁：</strong>即<strong>先等待的线程先获得锁</strong>，synchronized 实现的只是非公平锁。</li>
<li><strong>可实现选择性通知（锁可以绑定多个条件）：线程对象可以注册在指定的 Condition 中，从而可以有选择性的进行线程通知</strong>，在调度线程上更加灵活。 在使用notify/notifyAll()方法时，被通知的线程是由 JVM 选择的，用 ReentrantLock 类结合 Condition 实例可以实现“选择性通知” 。</li>
</ul>
</li>
</ul>
<ul>
<li><p><strong>性能已不是选择标准</strong></p>
<p><strong>在synchronized能满足你的需求的情况下，<mark>优先考虑使用 synchronized 关键字</mark>来进行同步！</strong></p>
<p><strong>优化后的synchronized和ReenTrantLock一样，在很多地方都是用到了<mark>CAS操作</strong></mark>。</p>
</li>
</ul>

            </div>
            <hr>
            <div>
              <div class="post-metas mb-3">
                
                  <div class="post-meta mr-3">
                    <i class="iconfont icon-category"></i>
                    
                      <a class="hover-with-bg" href="/categories/Java/">Java</a>
                    
                  </div>
                
                
                  <div class="post-meta">
                    <i class="iconfont icon-tags"></i>
                    
                      <a class="hover-with-bg" href="/tags/%E9%9D%A2%E8%AF%95/">面试</a>
                    
                      <a class="hover-with-bg" href="/tags/%E5%A4%9A%E7%BA%BF%E7%A8%8B/">多线程</a>
                    
                  </div>
                
              </div>
              
              
                <div class="post-prevnext row">
                  <article class="post-prev col-6">
                    
                    
                      <a href="/2020/09/30/09-30-ThreadLocal/">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">多线程之 ThreadLocal</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                      <a href="/2020/09/21/09-21-Markdown-Grammar-Guide/">
                        <span class="hidden-mobile">Markdown 简明语法手册</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </article>
                </div>
              
            </div>

            
          </article>
        </div>
      </div>
    </div>
    
      <div class="d-none d-lg-block col-lg-2 toc-container" id="toc-ctn">
        <div id="toc">
  <p class="toc-header"><i class="iconfont icon-list"></i>&nbsp;目录</p>
  <div class="toc-body" id="toc-body"></div>
</div>

      </div>
    
  </div>
</div>

<!-- Custom -->


    

    
      <a id="scroll-top-button" href="#" role="button">
        <i class="iconfont icon-arrowup" aria-hidden="true"></i>
      </a>
    

    
      <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v"
                 for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>
    

    
      <div class="col-lg-7 mx-auto nopadding-md">
        <div class="container custom mx-auto">
          <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/vin9712/cdnRes@cdn/blog/hexo/css/font.css">
        </div>
      </div>
    
  </main>

  <footer class="text-center mt-5 py-3">
  <div class="footer-content">
     <span>©2020 by Lin<br>驱动</span> <a href="https://hexo.io" target="_blank" rel="nofollow noopener">Hexo</a> <span>|&nbsp;主题</span> <a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener">Fluid</a> <div> <span id="timeDate">载入天数...</span> <span id="times">载入时分秒...</span> <script src="/js/mod/duration.js"></script> </div> <div> <p style="font-size: 18px; font-weight: bold;" id="hitokoto">:D 获取中...</p> <script src="/js/mod/hitokoto.js"></script> </div> 
  </div>
  

  

  
</footer>

<!-- SCRIPTS -->

  <script  src="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.js" ></script>
  <link  rel="stylesheet" href="https://cdn.staticfile.org/nprogress/0.2.0/nprogress.min.css" />

  <script>
    NProgress.configure({"showSpinner":false,"trickleSpeed":200})
    NProgress.start()
    document.addEventListener('DOMContentLoaded', function() {
      window.NProgress && window.NProgress.inc();
    })
    window.addEventListener('load', function() {
      NProgress.done();
    })
  </script>


<script  src="https://cdn.staticfile.org/jquery/3.5.1/jquery.min.js" ></script>
<script  src="https://cdn.staticfile.org/twitter-bootstrap/4.5.3/js/bootstrap.min.js" ></script>
<script  src="/js/debouncer.js" ></script>
<script  src="/js/events.js" ></script>
<script  src="/js/plugins.js" ></script>

<!-- Plugins -->


  
    <script  src="/js/lazyload.js" ></script>
  



  



  <script  src="https://cdn.staticfile.org/tocbot/4.12.0/tocbot.min.js" ></script>



  <script  src="https://cdn.staticfile.org/fancybox/3.5.7/jquery.fancybox.min.js" ></script>





  <script defer src="https://cdn.staticfile.org/clipboard.js/2.0.6/clipboard.min.js" ></script>




<!-- 1.8.5 的原版的不好用 还是换回来了 -->
<!-- 打字机特效 -->

  <script  src="https://cdn.staticfile.org/typed.js/2.0.11/typed.min.js" ></script>
    <script type="text/javascript">
        !function(e){var n,t={},o="jinrishici-token";function i(){return document.getElementById("jinrishici-sentence")||0!=document.getElementsByClassName("jinrishici-sentence").length}function c(){t.load(function(e){var n=document.getElementById("jinrishici-sentence"),t=document.getElementsByClassName("jinrishici-sentence");if(n&&(n.innerText=e.data.content),0!==t.length)for(var o=0;o<t.length;o++)t[o].innerText=e.data.content})}function r(e,n){var t=new XMLHttpRequest;t.open("get",n),t.withCredentials=!0,t.send(),t.onreadystatechange=function(n){if(4===t.readyState){var o=JSON.parse(t.responseText);"success"===o.status?e(o):console.error("今日诗词API加载失败，错误原因："+o.errMessage)}}}t.load=function(n){return e.localStorage&&e.localStorage.getItem(o)?function(e,n){return r(e,"https://v2.jinrishici.com/one.json?client=browser-sdk/1.2&X-User-Token="+encodeURIComponent(n))}(n,e.localStorage.getItem(o)):function(n){return r(function(t){e.localStorage.setItem(o,t.token),n(t)},"https://v2.jinrishici.com/one.json?client=browser-sdk/1.2")}(n)},e.jinrishici=t,i()?c():(n=function(){i()&&c()},"loading"!=document.readyState?n():document.addEventListener?document.addEventListener("DOMContentLoaded",n):document.attachEvent("onreadystatechange",function(){"complete"==document.readyState&&n()}))}(window); 
        // 输出指定数量空格+引用
        function writeSpace(len){
          len = (len > 10) ? (len > 31 ? 0 : 8) : len
          var space = ''
          for(var i = 0; i<len; i++){
            space += '&emsp;'
          }
          return space+"——";
        }

        // 执行打字机动效
        function startTyping(strs){
          var typed = new Typed('#subtitle', {
          strings: ['  ', strs],
          cursorChar: "_",
          typeSpeed: 50,
          loop: false,
          });
          typed.stop();
          $(document).ready(function () {
            $(".typed-cursor").addClass("h2");
            typed.start();
          }); 
        }
    </script>
  
    <script>
      // 非首页 则输出文章标题
      var strs = document.getElementById('subtitle').title + "&nbsp;";
      startTyping(strs);
    </script>
  


  <script  src="/js/local-search.js" ></script>
  <script>
    (function () {
      var path = "/local-search.xml";
      var inputArea = document.querySelector("#local-search-input");
      inputArea.onclick = function () {
        searchFunc(path, 'local-search-input', 'local-search-result');
        this.onclick = null
      }
    })()
  </script>









  <script  src="https://cdn.staticfile.org/mermaid/8.8.2/mermaid.min.js" ></script>
  <script>
    if (window.mermaid) {
      mermaid.initialize({"theme":"default"});
    }
  </script>







<!-- 主题的启动项 保持在最底部 -->
<script  src="/js/boot.js" ></script>



</body>
</html>
